--
-- Author: shineflag
-- Date: 2017-06-27 09:47:03
--
-- Desc: 用户一些基本信息的管理


local skynet = require "skynet"
local log = require "log"
local json = require("json")
local redis = require "skynet.db.redis"
local mysql = require "skynet.db.mysql"
local proto = require("json_proto")
local sconf = require("server_conf")
require("sutils")

local TAG = "UINFO"

--ginfo 中的hash key
local ukeys = {
	"mnick",
	"icon" ,
	"sex",
	"mstatus",
	"mactivetime",
	"mentrydays",
	"version",
	"nettype",
	"pay",
	"inviteid",
	"rtime",
	"sid",
}
--是否是用户的key
local isukeys = {
	["mnick"] = true,
	["icon"] = true ,
	["sex"] = true,
	["mstatus"] = true,
	["mactivetime"] = true,
	["mentrydays"] = true,
	["version"] = true,
	["nettype"] = true,
	["pay"] = true,
	["inviteid"] = true,
	["rtime"] = true,
	["sid"] = true,
}

local mdata_proxy   --用户金币信息
local rdb     --redis数据库
local poker_db   --mysql数据库
local change_mids = {}  --改变用户信息的mid
local access_mids = {}   --访问过的用户数据
local UPDATA_TIME = 60*100 --更新数据库的时间
local UBINFO_EXPIRE = 3600*24*7  --用户的基本信息缓存7天
local CMD = {}

local function connect_poker_db()
	local function on_connect(db)
		db:query("set charset utf8mb4")
		db:query("set names utf8")  --可以插入中文字符了
		log.e(TAG, "poker db connected!")
	end

	local mconf = require("mysql_conf")

	log.e(TAG,"start connect mysql %s:%d",mconf.host, mconf.port)
	poker_db = mysql.connect({
		host = mconf.host,
		port = mconf.port,
		database = mconf.database,
		user = mconf.user,
		password = mconf.password,
		max_packet_size=1024*1024,
		on_connect=on_connect
		})

	if not poker_db then
		log.e(TAG,"failed to connect db")
		skynet.exit()
	end
end

local function redis_connect()
	local rconfs = require("redis_conf")
	local rport = sconf["redis_mdata"]
	local rconf = rconfs[rport]
	local conf = {
		host = rconf.host,
		port = rconf.port,
		db = 0
	}
	log.e(TAG,"start connect redis %s:%d",conf.host, conf.port)
	rdb = redis.connect(conf)
end


--将redis 字符串数组 形式的结果转换成 table 形式
local function rdata2table(data)
	local t = {}
	for id = 1, #data, 2 do 
		t[data[id]] = data[id+1]
	end

	return t
end


--从mysql获取用户的游戏
local function mysql_uinfo(mid)
	local sql = string.format("SELECT mnick, sex, mstatus, mactivetime, mentrydays, version, nettype, pay, inviteid, rtime, sid FROM poker_userinfo WHERE mid=%d", mid)
	local res =  poker_db:query(sql)
	log.d(TAG,"after sql[%s] res[%s]",sql, json.encode(res))
	k,row_data = next(res)
	if not row_data then 
		log.d(TAG,"failed sql[%s] err[%s]",sql, res.err) 
		return nil 
	end
	return row_data 
end


--将data 更新到数据库
local function update_uinfo_db(mid,data)
	local sql = string.format("UPDATE poker_userinfo SET mnick='%s', sex=%d,mstatus=%d, mactivetime=%d, mentrydays=%d, version='%s', nettype='%s', pay=%d, inviteid=%d  WHERE mid=%d",
		data.mnick, data.sex, data.mstatus, data.mactivetime, data.mentrydays, data.version, data.nettype, data.pay, data.inviteid, mid)
	local res =  poker_db:query(sql)
	log.d(TAG,"after sql[%s] res[%s]",sql, json.encode(res))
end

--将用户的信息插入到redis
local function hmset_uinfo(mid,info)
	local ukey = string.format("ubinfo_%d",mid)
	local rt = {ukey}   --redis 用
	for _, v in pairs(ukeys) do 
		table.insert(rt,v)
		table.insert(rt,info[v] or 0)
	end

	local ret = rdb:hmset(rt)
	log.d(TAG,"ret[%s] hmset %s ",json.encode(ret),table.concat(rt, " "))
	
end

--从redis中获取用户的所有游戏信息
local function hgetuinfo( mid )
	local ukey = string.format("ubinfo_%d",mid)
	local ret  = rdb:hgetall(ukey)
	log.d(TAG,"ret[%s]",json.encode(ret))
	return rdata2table(ret)
end


--加减hash key 某字段 数值
local function hincr(key,field,num)
	local  param = {key,field,num}
	local ret = rdb:hincrby(param)
	log.d(TAG,"call HINCRBY %s  #ret[%s]",table.concat(param, " "),ret)
	if not ret  then
		log.e(TAG,"faild call HINCRBY %s",table.concat(param, " "))
		return false
	else
		return tonumber(ret)
	end
end

local function update()
	if next(change_mids) then
		local t = change_mids 
		change_mids = {} 
		for mid, _ in pairs(t) do 
			local data = hgetuinfo(mid)
			update_uinfo_db(mid, data)
		end
	end

	if next(access_mids) then
		local at = access_mids 
		access_mids = {}
		for mid, _ in pairs(at) do 
			local ukey = string.format("ubinfo_%d",mid)
			rdb:expire(ukey, UBINFO_EXPIRE)
		end
	end

end


--更新用户的信息
function CMD.update(mid, info)
	local t = {string.format("ubinfo_%d",mid)}
	for _,key in pairs(gkey) do 
		if info[key] then 
			table.insert(t, key)
			table.insert(t. info[key])
		end
	end
	return rdb:hmset(t)
end


--获取用户的所有游戏信息
function CMD.getuinfo( mid )
	access_mids[mid] = true
	local ukey = string.format("ubinfo_%d",mid)
	local ret  = rdb:hgetall(ukey)
	log.d(TAG,"ret[%s]",json.encode(ret))
	if not ret or not next(ret) then 

		local data = mysql_uinfo(mid)
		if data then 
			if not data.icon then data.icon = "file://dec/morentouxiang.png" end
			hmset_uinfo(mid, data)
			return true, data 
		else
			return false 
		end

	else
		return true, rdata2table(ret)
	end
end

--改变某个用户的某个字段的值
function CMD.cfield(mid, field, num)
	if not isukeys[field] then 
		return false 
	end
	CMD.getuinfo(mid)
	local ukey = string.format("ubinfo_%d",mid)
	local left = hincr(ukey, field, num)
	if left then 
		change_mids[mid] = true
	end
	return left
end

--改变某个用户的某个字段的值
function CMD.setfield(mid, field, val)
	if not isukeys[field] then 
		return false 
	end
	CMD.getuinfo(mid)
	local ukey = string.format("ubinfo_%d",mid)
	local ret = rdb:hset(ukey, field, val)
	log.d(TAG,"hset %s %s %s",ukey, field, val)
	if ret then 
		change_mids[mid] = true
	end
	return ret
end



--修改用户的名字
function CMD.changnick(mid, mnick)
	local ukey = string.format("ubinfo_%d",mid)
	local rt = {ukey}   --redis 用

	--只取10个宽度
	mnick = string.gsub(mnick, "%p","")
	local nick = string.utf8_sub_width(mnick,1,10)
	log.d(TAG,"user[%d] change mnick[%s] actual nick[%s]",mid,mnick, nick)
	table.insert(rt,"mnick")
	table.insert(rt,nick)
	local ret = rdb:hmset(rt)
	if ret then 
		change_mids[mid] = true
	end
	log.d(TAG,"ret[%s] hmset %s ",json.encode(ret),table.concat(rt, " "))
	return nick
end

function CMD.ginfo(mid, req)
	local ok,ginfo = skynet.call(mdata_proxy,"lua","getall",mid)
	local resp = {ret = 200, money=0,score=0,gold=0}
	if ok then 
		resp.money = tonumber(ginfo.money)  or 0
		resp.score = tonumber(ginfo.score) or 0
		resp.gold = tonumber(ginfo.gold) or 0
	end
	--log.d(TAG,"player[%d] money[%d] score[%d] gold[%d] type money[%s]", mid, resp.money,resp.score, resp.gold,type(resp.money))
	return proto.create_resp("uinfo.ginfo",resp)
end




skynet.start(function ( ... )

	connect_poker_db()
	redis_connect()
	mdata_proxy = skynet.uniqueservice "mdata"
	skynet.dispatch("lua", function( session,address, cmd,... )
		local f = CMD[cmd]
		if f then
			if session ~= 0 then
		   		skynet.ret(skynet.pack( f(...) ) )
		   	else
		   		f(...)
		   	end 
		else
		    log.e(TAG,string.format("address[%d] call not exist cmd[%s] ",address,cmd) )
	    end
	end)

	skynet.fork(function()
		while true do
			update()
			skynet.sleep(UPDATA_TIME)
		end
    end)   

end)